package org.thanos.demo.aop;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.lang.reflect.Method;
import java.nio.file.AccessDeniedException;
import java.util.Objects;

/**
 * 事件日志 切面,凡是带有 @ValidatePermission 以及@ResponseBody注解 控制器 都要进行 功能权限检查，
 * 若无权限，则抛出AccessDeniedException 异常，该异常将请求转发至一个控制器，然后将异常结果返回
 *
 * @author Administrator
 */
@Aspect
@Component
public class ValidatePermissionAspect {

    private static final Logger LOGGER = LoggerFactory.getLogger(ValidatePermissionAspect.class);

    @Pointcut("@annotation(org.thanos.demo.aop.ValidatePermission)")
    public void annotationPointCut(){}

    @Before("annotationPointCut()")
    public void doBefore(JoinPoint jp) throws IOException {
        Method sourceMethod = getSourceMethod(jp);
        if (Objects.nonNull(sourceMethod)) {
            ValidatePermission validatePermission = sourceMethod.getAnnotation(ValidatePermission.class);
            if (Objects.nonNull(validatePermission)) {
                int responseIndex = validatePermission.responseIndex();
                int tokenIndex = validatePermission.tokenIndex();
                Object[] args = jp.getArgs();
                if ((responseIndex >= 0 && responseIndex < args.length) && (tokenIndex >= 0 && tokenIndex < args.length)) {
                    ServerHttpResponse response = (ServerHttpResponse) args[responseIndex];
                    String token = String.valueOf(args[tokenIndex]);
                    //todo 业务
                    if ("sb".equals(token)) {
                        response.setStatusCode(HttpStatus.UNAUTHORIZED);
                        throw new AccessDeniedException("您无权操作！");
                    }
                }
            }
        }
    }

    private Method getSourceMethod(JoinPoint jp) {
        Method proxyMethod = ((MethodSignature) jp.getSignature()).getMethod();
        try {
            return jp.getTarget().getClass().getMethod(proxyMethod.getName(), proxyMethod.getParameterTypes());
        } catch (NoSuchMethodException | SecurityException e) {
            LOGGER.error(e.getMessage(), e);
        }
        return null;
    }
}